home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / src / submit / submit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-28  |  38.4 KB  |  1,297 lines

  1. #include "util.h"
  2. #include "mmdf.h"
  3.  
  4. /*
  5.  *     MULTI-CHANNEL MEMO DISTRIBUTION FACILITY  (MMDF)
  6.  *
  7.  *
  8.  *     Copyright (C) 1979,1980,1981  University of Delaware
  9.  *
  10.  *     Department of Electrical Engineering
  11.  *     University of Delaware
  12.  *     Newark, Delaware  19711
  13.  *
  14.  *     Phone:  (302) 738-1163
  15.  *
  16.  *
  17.  *     This program module was developed as part of the University
  18.  *     of Delaware's Multi-Channel Memo Distribution Facility (MMDF).
  19.  *
  20.  *     Acquisition, use, and distribution of this module and its listings
  21.  *     are subject restricted to the terms of a license agreement.
  22.  *     Documents describing systems using this module must cite its source.
  23.  *
  24.  *     The above statements must be retained with all copies of this
  25.  *     program and may not be removed without the consent of the
  26.  *     University of Delaware.
  27.  *
  28.  *
  29.  *     version  -1    David H. Crocker    March   1979
  30.  *     version   0    David H. Crocker    April   1980
  31.  *     version  v7    David H. Crocker    May     1981
  32.  *     version   1    David H. Crocker    October 1981
  33.  *
  34.  */
  35. /*  SUBMIT:  Mail enqueuer
  36.  *
  37.  *  May, 80 Dave Crocker    fix switch-setting in prm_ & pro_
  38.  *                          add eof check after text copy
  39.  *                          adr_ghost return PAST initial string ->
  40.  *                            modify use of pointer to be -1
  41.  *  Jun, 80 Dave Crocker    fix adr_ghost return to be 1 past
  42.  *                          mn_init, change fout to be 2, not dup(1)
  43.  *                          hdr_psfrom handle FLGFROM properly
  44.  *  Jul, 80 Dave Crocker    prm_parse, remove debug & fix default
  45.  *  Sep, 80 Jim Lieb        Conversion to V7 and standard io
  46.  *                            protocol replies go to stderr
  47.  *  Oct, 80 Dave Crocker    Minor mods to make V6 also (again) work
  48.  *  Nov, 80 Dave Crocker    Split off adr_submit, qf_submit, mgt_submit,
  49.  *                            & hdr_parse, for easier policy changes
  50.  *  Nov, 81 Dave Crocker    Switches case-insensitive
  51.  *  Jun 82  Dave Crocker    Add adruid proc/file address protection
  52.  *  Jul 82  Dave Crocker    qf_ -> mq_
  53.  */
  54.  
  55. #include <sys/stat.h>
  56. #include <pwd.h>
  57. #include "nexec.h"
  58. #include "ap.h"
  59. #include "ns.h"
  60.  
  61. extern LLog msglog;
  62. LLog *logptr = &msglog;
  63. extern struct ap_prevstruct   *ap_fle; /* parse state top of stack       */
  64.  
  65. extern char *locfullname;
  66. extern char *locfullmachine;
  67. extern char *quedfldir;            /* directory w/mail queue directories */
  68. extern char *cmddfldir;            /* directory w/mmdf commands          */
  69. extern char *logdfldir;            /* directory w/mmdf log files     */
  70. extern char *supportaddr;
  71. extern char *sitesignature;
  72.  
  73. jmp_buf retloc;                   /* address for longjmp()              */
  74. int     userid,                   /* id of user running me              */
  75.     effecid,                  /* id providing access priviledges    */
  76.     adruid;                   /* authorized addr, for file access   */
  77.  
  78. char    *username;                /* string login name of user running me */
  79. char    *mailid;                  /* string mailid of user running me     */
  80.  
  81. short   earlyret,                 /* caller already got return status   */
  82.     readadrs,                 /* will be directly fed address list  */
  83.     tracing;          /* enable submission tracing on fd2   */
  84.  
  85. extern char *mgt_parm();
  86. extern char *dupfpath();
  87. extern char *strdup();
  88. extern char *multcat();
  89. extern char *getmailid();
  90. extern char *malloc();
  91. extern char *strdup();
  92. extern struct passwd *getpwuid();
  93. extern ap_flget();
  94.  
  95. extern char *namdeliver;      /* name of mailer process             */
  96. extern char *pathdeliver;     /* file path to mailer proc.          */
  97. extern int  *regfdary;
  98. extern int  errno;
  99. extern int  sys_nerr;
  100. extern char *sys_errlist[];
  101.  
  102. char *prm_dupval();
  103.  
  104. LOCFUN prm_parse(), hdr_isacmpt();
  105.  
  106. /* *** constants  and temporaries *** */
  107. char    nltrm[] = "\n\377",        /* for gcread() */
  108.     nlnultrm[] = "\n\000\377",
  109.     nultrm[] = "\000\377";
  110.  
  111. /* *** pro_ *** */
  112. short   pro_doing = TRUE,         /* protocol-mode interaction vs. one- */
  113.                   /*    message "batch" submission?     */
  114.     pro_vfadr;                /* in protocol mode, indicate         */
  115.                   /*    acceptance of each address      */
  116. char    pro_buf[BUFSIZ];      /* buffer pro_ output                 */
  117.  
  118. /* */
  119. /* *** mq_ *** */
  120.  
  121. extern FILE *mq_mffp;             /* pointerto message text file buffer */
  122. extern char *mq_munique;          /* unique part of message queue name  */
  123.  
  124. /* *** ch_ *** */
  125. #include "ch.h"
  126. extern Chan **ch_tbsrch;
  127.  
  128. /* *** adr_ *** */
  129. #include "adr_queue.h"
  130. #include "msg.h"
  131. extern char *adr_fulldmn;       /* SEK - name for 'full' domain name    */
  132. extern char *adr_fmc;           /* name of 'full' machine               */
  133.  
  134. /* *** tx_ *** */
  135. long tx_msize;
  136.  
  137. /* *** hdr_ *** */
  138. #include "hdr.h"
  139. #define MAXACMPT    10
  140.  
  141. char   *hdr_cmpt[MAXACMPT];       /* where to extract addresses from    */
  142.  
  143. short     hdr_numadrcmpt;         /* number of components to search     */
  144.                   /*    for addresses in msg text       */
  145. short   hdr_extractadr;           /* tx_stormsg extract addrs?          */
  146.  
  147. /* *** mgt_ *** */
  148. extern char   *mgt_txsrc;         /* text to add to Source-Info cmpnt   */
  149. extern int    mgt_inalias;        /* SEK - is address extracted from    */
  150.                   /* alias file                         */
  151.  
  152. /* *** auth_ *** */
  153. extern char auth_msg[];         /* message of reason for auth refusal   */
  154.  
  155. /* *** dlv_ *** */
  156. short   dlv_watch;                /* user want to watch the send?       */
  157. int    dlv_flgs;                 /* flags to store into first line     */
  158.                   /*  of address list (e.g. RETCITE)    */
  159.  
  160. /* *** ut_ *** */
  161. char   *ut_alloc ();
  162. short   ut_eofhit,                /* eof encountered on ut_stdin        */
  163.     ut_msgend;                /* null/eof encountered on ut_stdin   */
  164.  
  165. /* ******  (mn_)  MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN  ****** */
  166.  
  167. LOCVAR    char *mn_aptr;          /* current position on buffer   */
  168. LOCVAR    char mn_abuf[LINESIZE]; /* address buffer               */
  169.  
  170. LOCFUN
  171.     mn_adrin ()            /* main   input given to alst_proc    */
  172. {
  173.     if (mn_aptr == (char *)1) {
  174. #ifdef DEBUG
  175.         ll_log (logptr, LLOGFTR, "mn_adrin need newline");
  176. #endif
  177.         if (ut_stdin(mn_abuf, sizeof(mn_abuf), nltrm, NOTOK) <= 0
  178.            || strequ ("!\n", mn_abuf))
  179.         mn_aptr = (char *) 0;   /* disable future reading     */
  180.         else
  181.         mn_aptr = mn_abuf;
  182.     }
  183.     if (mn_aptr == (char *)0) {
  184. #ifdef DEBUG
  185.         ll_log (logptr, LLOGBTR, "mn_adrin eof or err");
  186. #endif
  187.         return (0);                 /* permanent eof                */
  188.     }
  189.  
  190.     switch (*mn_aptr) {
  191.     case '\n':
  192.     case '\0':                      /* end on bang/newline/bang */
  193.         mn_aptr = (char *)1;      /* indicate we need another line */
  194.         return (0);                 /* note end of this address     */
  195.     }
  196.  
  197.     return (*mn_aptr++);
  198. }
  199.  
  200. /*
  201.  *  Function to re-sync input.  This is needed for the interactive
  202.  *  input function because the other side is expecting exactly one
  203.  *  reply per line sent.  alst_proc might parse two addresses in one line.
  204.  */
  205. mn_arset()
  206. {
  207.     mn_aptr = (char *)1;
  208. }
  209.  
  210. mn_aread ()
  211. {
  212.     mn_aptr = (char *)1;      /* flag as needing a new line */
  213.     mgt_inalias = FALSE;      /* reading addresses from input          */
  214.  
  215.     (void) alst_proc (mn_adrin, TRUE, mn_arset, (char **) 0);
  216.  
  217.     mn_aptr = (char *) 0;
  218. }
  219.  
  220. /* */
  221.  
  222. main (argc, argv)                 /*   MAIN MAIN MAIN MAIN MAIN MAIN    */
  223. int       argc;
  224. char   *argv[];
  225. {
  226.     umask(0);
  227.     mmdf_init (argv[0]);
  228. #ifdef NAMESERVER
  229.     ns_settimeo(NS_UIPTIME);    /* set an initial timeout */
  230. #endif
  231.     mn_usinit ();                 /* initial info on who is running us  */
  232.     mn_init (argc, argv);         /* parse args, alloc buffers.         */
  233.     mn_dirinit ();                /* chdir into quedfldir                 */
  234.     mgt_init ();
  235.     mq_winit ();                  /* info on queue directories          */
  236.  
  237.     for (setjmp (retloc);       /* return here, after err_msg         */
  238.         !ut_eofhit;)          /* no more input?                     */
  239.     {
  240.     if (pro_doing)
  241.         if (pro_init () != OK)
  242.         break;            /* all done                           */
  243.  
  244.     mq_creat ();              /* set-up the queue files including   */
  245.                   /*    status info in address list     */
  246.  
  247.     if (readadrs)            /* explicit address list being given? */
  248.         mn_aread ();
  249.  
  250.     if (ut_msgend)            /* can't do much with only addr list  */
  251.         err_abrt (RP_EOF, "Input ended prior to processing text");
  252.  
  253.     tx_stormsg ();            /* queue & authenticate message       */
  254.  
  255.     if (pro_doing && ut_eofhit)
  256.         err_abrt (RP_EOF, "Premature eof during text copy");
  257.  
  258.     mgt_aend ();             /* perform any ending address policy  */
  259.  
  260.     lnk_filall (dlv_flgs);
  261.                   /* put address list into its file     */
  262.  
  263.     lnk_freeall ();
  264.  
  265.     mq_eomsg ();              /* move to real queue directory       */
  266.  
  267. #ifdef DEBUG
  268.     ll_log (logptr, LLOGPTR, "msg done -- do deliver?");
  269. #endif
  270.  
  271.     dlv_invoke ();            /* Maybe give the message a mailer    */
  272.                   /* Will acknowledge message queueing */
  273.     }
  274.     exit (RP_OK);
  275. }
  276. /* */
  277.  
  278. mn_init (argc, argv)              /* basic process initialization       */
  279. int       argc;
  280. char   *argv[];
  281. {
  282.     register short     tmp;
  283.  
  284.     prm_init ();                  /* set default values                 */
  285.     for (tmp = 1; tmp < argc; tmp++)
  286.     {                             /* parse any arguments                */
  287.     if (*argv[tmp] == '-')
  288.     {
  289.         pro_doing = FALSE;    /* presence of arguments => one-shot  */
  290.         prm_parse (&argv[tmp][1]);
  291.     }                         /* parse the switch string            */
  292.     else
  293.         mgt_parm (argv[tmp]); /* let management module analyze it   */
  294.     }
  295.  
  296.     if (!pro_doing)               /* protocol mode will do its own      */
  297.     prm_end ();               /* cleanup & evaluate state           */
  298. }
  299. /* */
  300.  
  301. mn_usinit ()                      /* get info on who is running me      */
  302. {
  303.     register char *midp;
  304.     register struct passwd *pw;
  305.  
  306.     getwho (&userid, &effecid);   /* who is running me?                 */
  307. #ifdef DEBUG
  308.     ll_log (logptr, LLOGBTR, "user=%d, effec=%d", userid, effecid);
  309. #endif
  310.  
  311.     if((pw = getpwuid(userid)) == NULL
  312.       || (midp = getmailid(pw->pw_name)) == NULL)
  313.     err_abrt (RP_LIO, "No login/mailid for UID %d, call Support.",
  314.         userid);
  315.  
  316.     username = strdup (pw -> pw_name);
  317.     mailid = strdup (midp);
  318.  
  319.     if (effecid == userid)        /* being run by MMDF                  */
  320.     adruid = 0;               /* full privileges                    */
  321.     else
  322.     adruid = userid;          /* uid for file/process redirection   */
  323. #ifdef  UCL
  324.     if (adruid == 2)            /* fix for authorization for UCL        */
  325.     adruid = 0;
  326. #endif
  327. }
  328.  
  329. mn_dirinit ()                     /* current loc? chdir to home; setuid */
  330. {
  331.     if (chdir (quedfldir) == NOTOK) /* change wdir into mail queues       */
  332.     err_abrt (RP_LIO, "Unable to change directory.");
  333.  
  334.     setuid (userid);              /* so we have the user's privileges   */
  335.                   /*   to access address files          */
  336. }
  337. /* ******************  (prm_) USER PARAMETER HANDLING  *************** */
  338.  
  339. prm_init ()                       /* set default user-settable vals     */
  340. {
  341.  
  342.     mgt_minit ();                /* initialize management settings     */
  343.  
  344.     while (hdr_numadrcmpt-- > 0)   /* free any previous component names  */
  345.     free (hdr_cmpt[hdr_numadrcmpt]);
  346.  
  347.     hdr_numadrcmpt =
  348.     dlv_flgs = 0;
  349.  
  350.     readadrs =
  351.     hdr_extractadr =
  352.     pro_vfadr =
  353.     dlv_watch =
  354.     earlyret =  FALSE;
  355.  
  356.     adr_fulldmn = locfullname;
  357.     if (locfullmachine && isstr (locfullmachine))
  358.         adr_fmc = locfullmachine;
  359.     else
  360.         adr_fmc = locfullname;
  361. }
  362.  
  363. prm_end ()                        /* evaluate final settings            */
  364. {
  365.     if (!pro_doing)               /* no protocol => a unix "command"    */
  366.     domsg = TRUE;
  367.  
  368.     if (!hdr_extractadr)           /* not building list from msg text,   */
  369.     readadrs = TRUE;         /*    so take from explicit list      */
  370.  
  371.     mgt_pend ();                  /* end of parm specifications         */
  372. }
  373. /* */
  374.  
  375. LOCFUN
  376.     prm_parse (parmstrt)      /* parse spec & set switches          */
  377.     char *parmstrt;               /* note beginning of parm             */
  378. {
  379.     register char  *parmptr;      /* pointer to text of specification   */
  380.  
  381.     parmptr = parmstrt;
  382.     FOREVER
  383.     switch (*parmptr++)       /* read until end of list             */
  384.     {
  385.     case '\0':
  386.     case '\n':
  387.         return;               /* all done                           */
  388.     case ' ':
  389.     case '\t':                /* skip linear white space            */
  390.     case '-':                 /* switch-char got through            */
  391.         continue;
  392.  
  393.     case 'L':           /* Specify alternate logfile, SU/MMDF only */
  394.         if (adruid == 0 && *parmptr) {
  395.             char *cp;
  396.                 
  397.                 switch (*(parmptr = prm_dupval(parmptr, &cp)))
  398.                 {                     
  399.                     case ',':     /* skip to the last char processed    */
  400.                         err_msg (RP_PARM, "Invalid parameter character ','");
  401.                 
  402.                     case '*':
  403.                         parmptr++;
  404.                 }
  405.         ll_log (logptr, LLOGFST, "Logfile is '%s'", cp);
  406.         logptr->ll_file = dupfpath(cp, logdfldir);
  407.         }
  408.         break;
  409.  
  410.     case 'V':               /* Specify alternate level, SU/MMDF only */
  411.         if (adruid == 0 && *parmptr) {
  412.             char *cp;
  413.         int level;
  414.                 
  415.                 switch (*(parmptr = prm_dupval(parmptr, &cp)))
  416.                 {                     
  417.                     case ',':     /* skip to the last char processed    */
  418.                         err_msg (RP_PARM, "Invalid parameter character ','");
  419.                 
  420.                     case '*':
  421.                         parmptr++;
  422.                 }
  423.         ll_log (logptr, LLOGFST, "Loglevel '%s'", cp);
  424.         if ((level = tai_llev (1, &cp)) > 0)
  425.             logptr->ll_level = level;
  426.         }
  427.             break;
  428.  
  429.         case 'W':
  430.             tracing = TRUE;
  431.             break;
  432.  
  433.     case 'b':                 /* deliver to mailbox AND tty (obsolete) */
  434.         break;
  435.  
  436.     case 'c':                 /* only CITATION in returm mail, not  */
  437.         dlv_flgs |= ADR_CITE;
  438.         break;                /*   full copy of text                */
  439.  
  440.     case 'd':                 /* don't force through DELAY channel */
  441.         mgt_parm ("d");
  442.         break;
  443.  
  444.     case 'f':                 /* add FROM text to Source-Info field */
  445.         switch (*(parmptr = prm_dupval (parmptr, &mgt_txsrc)))
  446.         {
  447.         case ',':
  448.         case '*':
  449.             parmptr++;
  450.         }
  451.         break;
  452.  
  453.     case 'h':                 /* hostname of relay source           */
  454.         switch (*(parmptr = mgt_parm (&parmptr[-1])))
  455.         {                     /* let management module process it   */
  456.         case ',':         /* skip to the last char processed    */
  457.             err_msg (RP_PARM, "Invalid parameter character ','");
  458.  
  459.         case '*':
  460.             parmptr++;
  461.         }
  462.         break;
  463.  
  464.     case 'i':                 /* RELAYING, "via" us, "INDIRECTLY"   */
  465.         switch (*(parmptr = mgt_parm (&parmptr[-1])))
  466.         {                     /* let management module process it   */
  467.         case ',':         /* skip to the last char processed    */
  468.             err_msg (RP_PARM, "Invalid parameter character ','");
  469.  
  470.         case '*':
  471.             parmptr++;
  472.         }
  473.         break;
  474.  
  475.     case 'j':                 /* we are the delay channel !!        */
  476.         mgt_parm ("j");
  477.         break;
  478.  
  479.     case 'k':                 /* Set nameserver timeouts */
  480.         switch (*(parmptr = mgt_parm (&parmptr[-1])))
  481.         {                     /* let management module process it   */
  482.         case ',':         /* skip to the last char processed    */
  483.             err_msg (RP_PARM, "Invalid parameter character ','");
  484.  
  485.         case '*':
  486.             parmptr++;
  487.         }
  488.         break;
  489.  
  490.     case 'l':                 /* send LOCAL mail immediately        */
  491.         mgt_parm ("l");       /* fork a mailer for it               */
  492.         break;
  493.  
  494.     case 'm':                 /* send just to MAILBOX (obsolete option) */
  495.         break;
  496.  
  497.     case 'n':                 /* send "NET" mail immediately        */
  498.         mgt_parm ("n");       /* fork a mailer for it               */
  499.         break;
  500.  
  501.     case 'q':                 /* do not return a copy on errors     */
  502.         dlv_flgs |= ADR_NORET;
  503.         break;
  504.  
  505.     case 'r':                 /* send RETURN mail to invoker        */
  506.         mgt_parm ("r");       /*    and not explicit specification  */
  507.         break;
  508.  
  509.     case 's':                 /* get RETURN from Sender info        */
  510.         mgt_parm ("s");       /*    and not explicit specification  */
  511.         break;
  512.  
  513.     case 't':                 /* TRUST me; don't authenticate       */
  514.         mgt_parm ("t");
  515.         break;
  516.  
  517.     case 'u':                 /* (close to 't'); no authentication  */
  518.         mgt_parm ("u");
  519.         break;
  520.  
  521.     case 'v':                 /* Protocol mode; VERIFY each address */
  522.         pro_vfadr = TRUE;     /*    as received                     */
  523.         break;
  524.  
  525.     case 'w':                 /* user wants to WATCH a delivery try */
  526.         dlv_watch = TRUE;
  527.         break;
  528.  
  529.     case 'g':                 /* GET cmpts addrs AND explicit ones  */
  530.         readadrs = TRUE;     /* DROP ON TRHOUGH                    */
  531.     case 'x':                 /* EXTRACT addrs from cmpnts          */
  532.         hdr_extractadr = TRUE; /* 'x' [name *(',' name)] '*'         */
  533.         while (hdr_numadrcmpt < MAXACMPT)
  534.         switch (*(parmptr = prm_dupval (parmptr,
  535.                 &(hdr_cmpt[hdr_numadrcmpt++]))))
  536.         {
  537.             case ',':
  538.             parmptr++;
  539.             continue;
  540.  
  541.             case '*':
  542.             case '\n':
  543.             parmptr++;
  544.  
  545.             case '\0':
  546.             goto cmptend;
  547.         }
  548.     cmptend:
  549.         hdr_cmpt[hdr_numadrcmpt] = 0;
  550.         break;
  551.  
  552.     case 'z':                 /* do not send non-delivery warnings  */
  553.         dlv_flgs |= ADR_NOWARN;
  554.         break;
  555.  
  556.     default:
  557.         err_msg (RP_PARM, "Invalid parameter character '%c' in '%s'",
  558.             parmptr[-1], parmstrt);
  559.     }
  560. }
  561. /* */
  562.  
  563. char *
  564.     prm_dupval (start, into)  /* get text; dup to into; return ptr  */
  565.                   /*     to last char in orig str       */
  566. char   *start;                    /* beginning of text to parse         */
  567. char  **into;                     /* where to put dup'd str             */
  568. {
  569.     register char   tchar;
  570.     register char  *strptr;
  571.  
  572.     for (strptr = start;; strptr++)
  573.     switch (*strptr)
  574.     {
  575.         case '*':
  576.         case ',':
  577.         case '\0':
  578.         case '\n':
  579.         tchar = *strptr;
  580.         *strptr = '\0';
  581.         *into = strdup (start);
  582.         *strptr = tchar;
  583.         return (strptr);  /* pass back pointer to last char     */
  584.     }
  585. }
  586. /* *************  (pro_)  PROTOCOL WITH CALLER  **************** */
  587.  
  588. pro_init ()                       /* read switches in protocol mode     */
  589. {
  590.     char linebuf[LINESIZE];
  591.  
  592. #ifdef DEBUG
  593.     ll_log (logptr, LLOGBTR, "pro_init ()");
  594. #endif
  595.  
  596.     (void) setbuf(stderr,pro_buf);
  597.  
  598.     ut_msgend = FALSE;
  599.  
  600.     if (ut_stdin (linebuf, sizeof linebuf, nlnultrm, NOTOK) == OK)
  601.     return (NOTOK);          /* done before we began.  tsk. tsk.   */
  602.  
  603.     prm_init ();
  604.     prm_parse (linebuf);         /* parse & use switches               */
  605.     prm_end ();
  606.     return (OK);
  607. }
  608. /* */
  609.  
  610. /* VARARGS2 */
  611. pro_reply (code, fmt, b, c, d) /* inform user of a status            */
  612. short     code;                     /* value from mmdfrply.h              */
  613. char   *fmt,
  614.        *b,
  615.        *c,
  616.        *d;
  617. {
  618.     register char  *errchar;
  619.  
  620. #ifdef DEBUG
  621.     ll_log (logptr, LLOGBTR, "pro_reply(%s)", rp_valstr (code));
  622.     ll_log (logptr, LLOGFTR, fmt, b, c, d);
  623. #endif
  624.  
  625.     if (pro_doing)                /* print each field, for exactness    */
  626.     putc(rp_gval (code), stderr);
  627.     else
  628.     {                             /* assume human watching              */
  629.     if (rp_isgood (code))  /* keep silent during success         */
  630.         return;
  631.     fprintf(stderr, "submit: ");      /* and noisy on errors                */
  632.     }
  633.     if (rp_isbad (code))
  634.     switch (rp_gval (code))
  635.     {
  636.         case RP_HUH:          /* not if it was a user error         */
  637.         case RP_PARM:
  638.         case RP_USER:
  639.         break;
  640.  
  641.         default:
  642.         if (errno > 0 && errno < sys_nerr)
  643.                   /* a system-call error; have to dance */
  644.         {                 /* around ending \n in sys_errlist    */
  645.             fprintf (stderr, "[ ");
  646.             for (errchar = sys_errlist[errno];
  647.                 !isnull (*errchar) && *errchar != '\n';
  648.                 errchar++)
  649.             putc(*errchar, stderr);
  650.             fprintf (stderr, " ] ");
  651.         }
  652.     }
  653.     fprintf(stderr, fmt, b, c, d);
  654.     putc('\n', stderr);
  655.     fflush(stderr);
  656. }
  657. /* ****************  (alst_)  PROCESS AN ADDRESS LIST  *************** */
  658.  
  659. alst_proc (inproc, errabrt, resync, badptr)  /* process text stream of addrs */
  660. int     (*inproc) ();           /* the function which gets address     */
  661.                 /*    chars; decides when finished    */
  662. int     errabrt;                /* abort on error?                    */
  663. int     (*resync) ();           /* the function that resyncs input      */
  664. char    **badptr;               /* place to stuff list of bad addresses */
  665. {
  666.     AP_ptr  local,             /* beginning of local-part */
  667.         domain,            /* basic domain reference */
  668.         route;             /* beginning of 733 forward routing */
  669.     AP_ptr  theptr;
  670.     int     retval;
  671.     int     anybad;
  672.     char    *msgptr;
  673.     char    *addrp;
  674.     char    *cp;
  675.     int     inalias;
  676.     char    *oldbad;
  677.  
  678. #ifdef DEBUG
  679.     ll_log (logptr, LLOGBTR, "alst_proc ()");
  680. #endif
  681.     anybad = RP_AOK;
  682.     inalias = mgt_inalias;      /* SEK hold value at this level */
  683.  
  684.     FOREVER
  685.     {
  686.     if ((theptr = ap_pinit (inproc)) == (AP_ptr) NOTOK)
  687.         err_abrt (LLOGTMP, "problem initializing for address parse");
  688.                   /* problem during parse               */
  689.  
  690.     switch( retval = ap_1adr ())
  691.     {                   /* get next address                         */
  692.         case NOTOK:
  693.         ap_sqdelete (theptr, (AP_ptr) 0);
  694.         ap_free (theptr);
  695.         if (!errabrt)           /* Keep on trucking...     */
  696.             anybad = RP_USER;
  697.         else if (pro_vfadr)    /* just tell caller & continue  */
  698.             err_gen (RP_USER, "Unable to parse address");
  699.         else              /* kiss off the whole message         */
  700.             err_msg (RP_USER, "Unable to parse address");
  701.         if (resync != 0)
  702.             (*resync)();
  703.         continue;       /*  Go get another address...  */
  704.  
  705.         case DONE:
  706. #ifdef DEBUG
  707.         ll_log( logptr, LLOGFTR, "alst_proc() done");
  708. #endif
  709.         ap_sqdelete (theptr, (AP_ptr) 0);
  710.         ap_free (theptr);
  711.         return (anybad);
  712.     }
  713.     mgt_inalias  = inalias;         /* take iniial value */
  714.  
  715.     if(ap_t2s (theptr, &addrp) != (AP_ptr)MAYBE) {
  716. #ifdef DEBUG
  717.         ll_log (logptr, LLOGBTR, "canonical addr: '%s'", addrp);
  718. #endif
  719.             if (tracing) {
  720.             printf("%s:  ", addrp);
  721.         fflush(stdout);
  722.         }
  723.         ap_t2parts (theptr, (AP_ptr *) 0, (AP_ptr*) 0,
  724.                     &local, &domain, &route);
  725.         if (theptr -> ap_obtype == APV_DTYP &&
  726.         lexequ (theptr -> ap_obvalue, "include"))
  727.         {
  728.         Chan    *lrval;
  729.         /*
  730.          *  Handle :include:/foo/bar@host, :include:file, <file, etc.
  731.          */
  732.         if (domain && (domain -> ap_obvalue)
  733.           && (lrval = ch_h2chan (domain -> ap_obvalue, 1))
  734.                             != (Chan *) OK)
  735.         {
  736.             if(lrval == (Chan *)MAYBE)
  737.             retval = RP_NS;
  738.             else {
  739.             cp = multcat (":Include:", local -> ap_obvalue, (char *)0);
  740.             free (local  -> ap_obvalue);
  741.             local -> ap_obvalue = cp;
  742.             retval = adr_check (local, domain, route);
  743.             }
  744.         }
  745.         else
  746.             retval = alst_gfil (local -> ap_obvalue);
  747.         }
  748.         else                      /* regular address */
  749.         retval = adr_check (local, domain, route);
  750.  
  751.         if(rp_gval(retval) == RP_NS)  /* can we use the delay channel */
  752.         retval = adr_dsubmit(addrp);
  753.     }
  754.         else
  755.             retval = RP_NS;
  756.  
  757.     if (errabrt)              /* we care about this address         */
  758.     {
  759.         if (rp_isbad (retval))
  760.         {                     /* error                              */
  761.         switch (rp_gval (retval))
  762.         {
  763.             case RP_NS:
  764.             if (tracing) {
  765.                 printf("Nameserver Timeout\n");
  766.                 fflush(stdout);
  767.             }
  768.             msgptr = "(%s) Nameserver Timeout in \"%s\"";
  769.             if (pro_vfadr)    /* just tell caller & continue */
  770.                 err_gen(RP_NS, msgptr, rp_valstr(retval), addrp);
  771.             else              /* kiss off the whole message */
  772.                 err_msg(RP_NS, msgptr, rp_valstr(retval), addrp);
  773.             goto bugout1;
  774.  
  775.             case RP_USER:
  776.             msgptr = "(%s) Unknown user name in \"%s\"";
  777.             break;
  778.  
  779.             case RP_BHST:
  780.             msgptr = "(%s) Unknown host/domain name in \"%s\"";
  781.             break;
  782.  
  783.             case RP_FOPN:
  784.             msgptr = "(%s) Unable to open address file \"%s\"";
  785.             break;
  786.  
  787.             case RP_NAUTH:
  788.             msgptr = "(%s) Bad authorization: %s";
  789.             if (pro_vfadr)    /* just tell caller & continue        */
  790.                 err_gen (RP_USER, msgptr, rp_valstr (retval), auth_msg);
  791.             else              /* kiss off the whole message         */
  792.                 err_msg (RP_USER, msgptr, rp_valstr (retval), auth_msg);
  793.             goto bugout1;
  794.  
  795.             default:
  796.             msgptr = "(%s) Cannot process address \"%s\"";
  797.         }
  798.         if (tracing) {
  799.             printf("Bad address\n");
  800.             fflush(stdout);
  801.         }
  802.         if (pro_vfadr)    /* just tell caller & continue        */
  803.             err_gen (RP_USER, msgptr, rp_valstr (retval),
  804.                               addrp, auth_msg);
  805.         else              /* kiss off the whole message         */
  806.             err_msg (RP_USER, msgptr, rp_valstr (retval),
  807.                               addrp, auth_msg);
  808.         }
  809.         else if (pro_vfadr) {
  810.         /* it's ok and we want to know that, too   */
  811.         if (pro_doing) {
  812.             if(rp_gval(retval) == RP_DOK)
  813.             pro_reply (RP_DOK, "Possibly a nice address \"%s\"",
  814.                                      addrp);
  815.             else
  816.             pro_reply (RP_AOK, "Nice address \"%s\"", addrp);
  817.  
  818.         }
  819.         else
  820.             printf ("%s: OK\n", addrp);
  821.         }
  822.     }
  823.     else if (rp_isbad (retval)) {
  824.         switch (retval)
  825.         {
  826.         case RP_NAUTH:
  827.         case RP_NS:
  828.             anybad = retval;
  829.             break;
  830.  
  831.         default:
  832.             anybad = RP_USER;
  833.             break;
  834.         }
  835.  
  836.         if (badptr) {
  837.             if (*badptr == (char *)0)
  838.                 *badptr = multcat(addrp, "\n", (char *) 0);
  839.             else {
  840.                 oldbad = *badptr;
  841.                 *badptr = multcat(oldbad, addrp, "\n", (char *) 0);
  842.                 free (oldbad);
  843.             }
  844.         }
  845.     }
  846.  
  847. bugout1:
  848.     ap_sqdelete (theptr, (AP_ptr) 0);
  849.     ap_free (theptr);
  850.     free (addrp);
  851.     if (resync != 0)
  852.         (*resync)();
  853.     }
  854.     /* NOTREACHED */
  855. }
  856. /* ******************  ADDRESS FILE INPUT  *************************** */
  857.  
  858. alst_gfil (file)                 /* read file address list             */
  859.     char    file[];               /* basic name of file                 */
  860. {
  861.     struct stat statbuf;
  862.     int oadruid;                 /* push old adruid onto stack */
  863.     static char themsg[] = "Can't get addresses from file '%s'";
  864.     char *badlist = (char *) 0;
  865.  
  866. #ifdef DEBUG
  867.     ll_log (logptr, LLOGBTR, "alst_gfil (%s)", file);
  868. #endif
  869.     if (tracing) {
  870.     printf("Including file %s\n", file);
  871.     fflush(stdout);
  872.     }
  873.     oadruid = adruid;
  874.  
  875.     if (ap_fpush (file) != OK)
  876.     {                           /* could not open the file */
  877.     ll_err (logptr, LLOGGEN, themsg, file);
  878.     return (RP_FOPN);
  879.     }
  880.  
  881.     fstat (fileno (ap_fle -> ap_curfp), &statbuf);
  882.  
  883.     if (effecid == statbuf.st_uid)
  884.     adruid = 0;             /* full privileges                    */
  885.     else                        /* uid for file/process redirection   */
  886.     adruid = statbuf.st_uid;
  887.  
  888. #ifdef DEBUG
  889.     ll_log (logptr, LLOGFTR, "adruid for file = %d", adruid);
  890. #endif
  891.  
  892.     mgt_inalias = FALSE;        /* getting addresses from file          */
  893.  
  894.     if (rp_isbad (alst_proc (ap_flget, FALSE, (int (*)())0 , &badlist))) {
  895.     struct  passwd *pw;
  896.     char    *cp;
  897.     char    linebuf[LINESIZE];
  898.  
  899.     ll_log (logptr, LLOGTMP, "Bad address in list-file %s", file);
  900.     if (tracing) {
  901.         printf ("Bad address in file %s\n", file);
  902.         fflush(stdout);
  903.     }
  904.     sprintf (linebuf, "%s %s", locfullname, sitesignature);
  905.     ml_init (NO, NO, linebuf, "Bad address in file");
  906.     ml_adr (supportaddr);
  907.     if( (pw = getpwuid (statbuf.st_uid))
  908.      && (cp = getmailid (pw->pw_name)) )
  909.         ml_adr (cp);
  910.     ml_aend();
  911.     ml_tinit();
  912.     sprintf (linebuf, "Found bad address in the file '%s'.\n\n", file);
  913.     ml_txt (linebuf);
  914.     if (badlist) {
  915.         sprintf (linebuf, "There were problems with:\n");
  916.         ml_txt (linebuf);
  917.         ml_txt (badlist);
  918.         free (badlist);
  919.         sprintf (linebuf, 
  920.     "\nThe remaining addresses in the file were used for submission.\n\n");
  921.         ml_txt (linebuf);
  922.     }
  923.     if (ml_end(OK) != OK)
  924.         ll_log (logptr, LLOGFAT, "Can't send to supportaddr");
  925.     }
  926.     ap_fpop ();
  927.  
  928. #ifdef DEBUG
  929.     ll_log (logptr, LLOGFTR, "done w/file");
  930. #endif
  931.     adruid = oadruid;
  932.     return (RP_AOK);
  933. }
  934. /* ***************  (tx_)  TRANSFER MESSAGE TEXT  ******************** */
  935.  
  936. tx_stormsg ()                     /* store message text into queue      */
  937. {                                 /* perform required processing        */
  938.     struct stat statbuf;
  939.     short len,
  940.     retval;
  941.     char linebuf[LINESIZE],       /* input line                         */
  942.      thename[LINESIZE];       /* name of the component              */
  943.     register char   lastchar;     /* to make sure message end with \n   */
  944.  
  945. #ifdef DEBUG
  946.     ll_log (logptr, LLOGPTR, "tx_stormsg ()");
  947. #endif
  948.  
  949.     mgt_hinit ();
  950.  
  951.     for (mq_txinit (), lastchar = '\n';
  952.      (len = ut_stdin (linebuf, sizeof linebuf, nlnultrm, NOTOK)) != OK &&
  953.      (retval = hdr_proc (linebuf, thename)) > HDR_EOH;
  954.      fputs (linebuf, mq_mffp))
  955.         lastchar = linebuf[len - 1];
  956.                   /* process headers & copy to file     */
  957.  
  958.     if (lastchar != '\n')         /* msgs must end with newline         */
  959.     putc ('\n', mq_mffp);
  960.  
  961.     mgt_hend ();          /* whatever policies apply overall    */
  962.                   /* includes Source-Info & Via         */
  963.  
  964.     putc ('\n', mq_mffp);         /* put out the blank line             */
  965.  
  966.     if (retval == HDR_NAM)        /* put out illegal first body line    */
  967.     fputs (linebuf, mq_mffp); /*  if any                            */
  968.  
  969.     if (!ut_msgend)               /* nothing to copy                    */
  970.     {
  971.         char buf[BUFSIZ];      /* Lets be efficient now        */
  972.  
  973.     for (lastchar = '\n';     /* copy the body                      */
  974.       (len = ut_stdin (buf, sizeof buf, nultrm, OK)) > 0;
  975.       fwrite (buf, sizeof(char), len, mq_mffp))
  976.         lastchar = buf[len - 1];
  977.  
  978.     if (lastchar != '\n')     /* msgs must end with newline         */
  979.         putc ('\n', mq_mffp);
  980.     }
  981.     fflush (mq_mffp);
  982.     fstat (fileno (mq_mffp), &statbuf);
  983.     tx_msize = st_gsize (&statbuf);
  984. }
  985. /* ******************  (hdr_)  PROCESS A HEADER  ********************* */
  986.  
  987. LOCVAR char *hdr_atxt;             /* hdr_in() passes to alst()      */
  988.  
  989. LOCFUN
  990.     hdr_in ()               /* adrs extracted from component text */
  991. {
  992.     if (hdr_atxt == (char *) 0)  /* nothing to give it                 */
  993.     return (EOF);
  994.  
  995.     switch (*hdr_atxt)
  996.     {
  997.     case '\0':
  998.     case '\n':            /* end of string, DROP ON THROUGH     */
  999.         hdr_atxt = (char *) 0;
  1000.         return (0);
  1001.     }
  1002.     return (*hdr_atxt++);
  1003. }
  1004. /* */
  1005.  
  1006. hdr_proc (theline, name)          /* process one header line            */
  1007.     char theline[],               /* the text                           */
  1008.      *name;                   /* old or new name of header          */
  1009. {
  1010.     char contents[LINESIZE];      /* where to put header contents       */
  1011.     int  thestate;
  1012.  
  1013. #ifdef DEBUG
  1014.     ll_log (logptr, LLOGBTR, "hdr_proc (%s)", theline);
  1015. #endif
  1016.  
  1017.     switch (thestate = hdr_parse (theline, name, contents))
  1018.     {
  1019.     case HDR_NAM:
  1020.         return (HDR_NAM);
  1021.  
  1022.     case HDR_EOH:
  1023.         return (HDR_EOH);
  1024.  
  1025.     case HDR_NEW:
  1026.     case HDR_MOR:
  1027.         break;
  1028.     }
  1029.  
  1030.     if (!mgt_hdr (name, contents, thestate))
  1031.     err_msg (RP_HUH, "Problem with component '%s'", name);
  1032.  
  1033.     if (hdr_extractadr && hdr_numadrcmpt > 0 && hdr_isacmpt (name))
  1034.     {                             /* add the addresses                  */
  1035.     hdr_atxt = contents;
  1036.     mgt_inalias = FALSE;      /* getting addresses from header      */
  1037.     (void) alst_proc (hdr_in, TRUE, (int (*)())0, (char **) 0);
  1038.     }
  1039.  
  1040.     return (HDR_OK);
  1041. }
  1042.  
  1043. LOCFUN
  1044.     hdr_isacmpt (name)        /* a component on extraction list?    */
  1045. register char   name[];           /* name of the test component         */
  1046. {
  1047.     register short    entry;
  1048.  
  1049. #ifdef DEBUG
  1050.     ll_log (logptr, LLOGBTR, "hdr_isacmpt(%s)", name);
  1051. #endif
  1052.     for (entry = 0; entry < hdr_numadrcmpt && hdr_cmpt[entry]; entry++)
  1053.     if (lexequ (name, hdr_cmpt[entry]))
  1054.         return (TRUE);
  1055.     return (FALSE);
  1056. }
  1057. /* *****************  (dlv_)  INVOKE DELIVER PROCESS  *************** */
  1058.  
  1059. dlv_invoke ()                     /* maybe try immediate transmission   */
  1060. {
  1061.     Chan    **chanptr;
  1062.     char    temppath[LINESIZE];
  1063.     char dochans[LINESIZE];
  1064.     int     oldpid;               /* what channels to send              */
  1065.     int     proctyp,              /* type of process invocation         */
  1066.         dowait;               /* parent status after child invoke   */
  1067.  
  1068. #ifdef DEBUG
  1069.     ll_log (logptr, LLOGBTR, "dlv_invoke ()");
  1070. #endif
  1071.  
  1072.     strcpy (dochans, "-c");       /* switch, indicating chans to run    */
  1073.  
  1074.     for (proctyp = dowait = 0, chanptr = ch_tbsrch; *chanptr != 0; chanptr++)
  1075.     if ((*chanptr) -> ch_access & DLVRDID)
  1076.     {
  1077. #ifdef DEBUG
  1078.         ll_log (logptr, LLOGFTR, "do: %s (%s)",
  1079.         (*chanptr) -> ch_show, (*chanptr) -> ch_name);
  1080. #endif
  1081.         strcat (dochans, (*chanptr) -> ch_name);
  1082.         strcat (dochans, ",");
  1083.         proctyp = SPNEXEC;    /* default to detached send           */
  1084.     }
  1085.     dochans[strlen (dochans) - 1] = '\0';    /* zap last comma */
  1086.  
  1087.     if (proctyp == 0)             /* nothing to send immediately        */
  1088.     {
  1089.     pro_reply (RP_MOK, "Submitted & queued (%s)", mq_munique);
  1090.     earlyret = TRUE;          /* note that we already ok'd          */
  1091.     return;
  1092.     }
  1093.     if (dlv_watch)                /* watch immediate transmissions?     */
  1094.     {
  1095.     proctyp = FRKEXEC;        /* do it via attached child           */
  1096.     dowait = FRKWAIT | FRKPIGO;
  1097.                   /* parent not interruptable til end   */
  1098.     regfdary[1] = 1;
  1099.     }
  1100.     else
  1101.     {
  1102.     pro_reply (RP_MOK, "Submitted & immediates started (%s)", mq_munique);
  1103.     earlyret = TRUE;          /* note that we already ok'd          */
  1104.     regfdary[1] = open ("/dev/null", 1);
  1105.                   /* no output to caller                */
  1106. #ifdef DEBUG
  1107.     ll_log (logptr, LLOGFTR, "null opened");
  1108. #endif
  1109.     }
  1110.  
  1111.     getfpath (pathdeliver, cmddfldir, temppath);
  1112.  
  1113. #ifdef DEBUG
  1114.     ll_log (logptr, LLOGBTR,
  1115.         "%s (%s, %s)", temppath, mq_munique, dochans);
  1116. #endif
  1117.     ll_close (logptr);        /* free it for deliver                */
  1118.  
  1119.     oldpid = getpid ();
  1120.  
  1121.     if (nexecl (proctyp, dowait|FRKCIGO|FRKERRR , regfdary,
  1122.         temppath, namdeliver, mq_munique, "-d",
  1123.         dochans, (dlv_watch) ? "-w" : (char *)0, (char *)0) == NOTOK)
  1124.     if (getpid () != oldpid)      /* problem with the child             */
  1125.     {
  1126.         printx ("Problem running delivery process\n");
  1127.         ll_err (logptr, LLOGTMP,
  1128.             "Unable to run %s '%s'", namdeliver, temppath);
  1129.         exit (RP_MECH);
  1130.     }
  1131.  
  1132.     if (regfdary[1] != 1)         /* it was opened on /dev/null         */
  1133.     close (regfdary[1]);
  1134.     if (dlv_watch)            /* if not already noted               */
  1135.     pro_reply (RP_MOK, "Done mailing (%s)", mq_munique);
  1136.  
  1137. }
  1138. /* ****************  (err_)  GENERAL ERROR-HANDLING  ***************** */
  1139.  
  1140. /* VARARGS2 */
  1141. err_abrt (code, fmt, b, c, d)  /* terminate the process              */
  1142. short     code;                     /* a mmdfrply.h termination code      */
  1143. char   *fmt,
  1144.        *b,
  1145.        *c,
  1146.        *d;
  1147. {
  1148.     mq_clear();                 /* Just to be sure. */
  1149.     if (setjmp (retloc) == 0)   /* hack; force err_msg return to here */
  1150.     err_msg (code, fmt, b, c, d);
  1151.     exit (code);                  /* pass the reply code to caller      */
  1152. }
  1153.  
  1154.  
  1155. /* VARARGS2 */
  1156. err_msg (code, fmt, b, c, d)   /* end processing for current message */
  1157. short     code;                     /* see err_abrt explanation           */
  1158. char   *fmt,
  1159.        *b,
  1160.        *c,
  1161.        *d;
  1162. {
  1163. #ifdef DEBUG
  1164.     ll_log (logptr, LLOGBTR, "err_msg ()");
  1165. #endif
  1166.     err_gen (code, fmt, b, c, d); /* includes sending reply             */
  1167.     if (!ut_eofhit)               /* get rid of rest of input stream    */
  1168.     ut_suckup ();
  1169.     mq_clear ();                  /* eliminate temporary files          */
  1170.     lnk_freeall();                /* wipe out the current address list  */
  1171.     if (pro_doing)                /* more messages ok in protocl mode   */
  1172.     longjmp (retloc, TRUE);
  1173.     else
  1174.     printx ("submit: message submission aborted\n");
  1175.     exit (code);                  /* otherwise, goodbye                 */
  1176. }
  1177.  
  1178. /* VARARGS2 */
  1179. err_gen (code, fmt, b, c, d)   /* standard error processing          */
  1180. short     code;                /* see err_abrt, for explanation      */
  1181. char   *fmt,
  1182.        *b,
  1183.        *c,
  1184.        *d;
  1185. {
  1186.     char newfmt[LINESIZE];        /* for printf                         */
  1187.  
  1188. #ifdef DEBUG
  1189.     ll_log (logptr, LLOGBTR, "err_gen(%s)", rp_valstr (code));
  1190. #endif
  1191.     if (rp_isgood (code))         /* it wasn't an error                 */
  1192.     return;
  1193.  
  1194.     switch (rp_gval (code))       /* log the error?                     */
  1195.     {
  1196.     case RP_HUH:              /* not if it was a user error         */
  1197.     case RP_PARM:
  1198.     case RP_USER:
  1199.         sprintf (newfmt, "%s %s", "xin", fmt);
  1200.         ll_log (logptr, LLOGFST, newfmt, b, c, d);
  1201.         break;
  1202.  
  1203.     default:
  1204.         sprintf (newfmt, "%s  %s", "err [ ABEND (%s) ] ", fmt);
  1205.         ll_err (logptr, LLOGFAT, newfmt, rp_valstr (code), b, c, d);
  1206.     }
  1207.  
  1208.     if (!earlyret)                /* haven't already sent reply         */
  1209.     pro_reply (code, fmt, b, c, d);
  1210. }
  1211. /* ******************  (ut_)  UTILITY ROUTINES  ********************** */
  1212.  
  1213. ut_stdin (buffer, buflen, brkset, longok) /* read from primary input    */
  1214. register char  *buffer;           /* where to put null-ended input      */
  1215. int    buflen;              /* length of buffer */
  1216. char    *brkset;                  /* what characters to end on          */
  1217. int     longok;                   /* long lines are allowed if == OK    */
  1218. {
  1219.     register int      len;        /* number of characters read          */
  1220.  
  1221. /*  brkset must always include null ('\000'), which is the end-of-message
  1222.  *  indicator.  if null is the terminator, len is decremented.  i.e.,
  1223.  *  null is not allowed to pass as an input character, tho its occurrence
  1224.  *  is noted by ut_msgend.
  1225.  */
  1226.  
  1227. #ifdef DEBUG
  1228.     ll_log (logptr, LLOGBTR, "ut_stdin (brk='%s')", brkset);
  1229. #endif
  1230.  
  1231.     if (ut_msgend || ut_eofhit)
  1232.     {
  1233. #ifdef DEBUG
  1234.     ll_log (logptr, LLOGBTR, "(eof terminated last read)");
  1235. #endif
  1236.     return (0);              /* signal eof, for this read          */
  1237.     }
  1238.  
  1239.     len = gcread (stdin, buffer, buflen - 1, brkset);
  1240.     switch (len)
  1241.     {
  1242.     case -1:
  1243.         err_abrt (RP_LIO, "Error reading data from control stream");
  1244.  
  1245.     case 0:
  1246. #ifdef DEBUG
  1247.         ll_log (logptr, LLOGBTR, "EOF");
  1248. #endif
  1249.         ut_msgend =
  1250.         ut_eofhit = TRUE;
  1251.         buffer[0] = '\0';
  1252.         return(0);
  1253.     }
  1254.     if (longok != OK && len == (buflen - 1))
  1255.     err_abrt (RP_NO, "Input line to submit longer than %d characters",
  1256.             buflen - 2);
  1257.  
  1258.     if (isnull (buffer[len - 1])) {
  1259.     --len;            /* strip null off end                 */
  1260.     ut_msgend = TRUE; /* also note end of message         */
  1261.     } else
  1262.     buffer[len] = '\0';
  1263.  
  1264. #ifdef DEBUG
  1265.     ll_log (logptr, LLOGFTR, "returning: \"%s\"", buffer);
  1266. #endif
  1267.     return (len);
  1268. }
  1269. /* */
  1270.  
  1271. ut_suckup ()                      /* skip rest of message input stream  */
  1272. {                                 /*    to null (not eof)               */
  1273.     register int c;
  1274.  
  1275.     if (!ut_msgend && !ut_eofhit)
  1276.     {
  1277.     while ((c = getc (stdin)) != EOF)
  1278.         if (isnull (c) && pro_doing)
  1279.         {
  1280.         ut_msgend = TRUE;
  1281.         return;
  1282.         }
  1283.     ut_eofhit = TRUE;
  1284.     }
  1285. }
  1286.  
  1287. char   *
  1288.     ut_alloc (numbytes)       /* allocate some memory               */
  1289. unsigned  numbytes;                 /* duh... number of bytes to allocate */
  1290. {
  1291.     register char  *thebytes;
  1292.  
  1293.     if ((thebytes = malloc (numbytes)) == NULL)
  1294.     err_abrt (RP_MECH, "No more storage available");
  1295.     return (thebytes);
  1296. }
  1297.